home *** CD-ROM | disk | FTP | other *** search
- #include <Aliases.h> /* for ResolveAlias in our coercion routine */
- #include <Script.h> /* for GetMBarHeight */
- #include <GestaltEqu.h>
- #include <Errors.h>
-
- #include "SampleDefs.h"
- #include "Sample.h"
- #include "SampleErrors.h"
- #include "SampleFileIO.h"
- #include "SampleMain.h"
- #include "SamplePrint.h"
- #include "SampleAEvt.h"
-
-
- struct pairs{
- AEKeyword theAEKeyWord;
- long theRefcon;
- };
- typedef struct pairs pairs;
- static pairs keyWordsToInstall[] = { { kAEOpenApplication, kAEOpenApplication },
- { kAEOpenDocuments, kAEOpenDocuments },
- { kAEPrintDocuments, kAEPrintDocuments },
- { kAEQuitApplication, kAEQuitApplication },
- { kAEAnswer, kAEAnswer },
- { traeEchoID, traeEchoID },
- { traeMoveFrontWindowMsgID, traeMoveFrontWindowMsgID }};
-
- #pragma segment Main
- /************************************************************************************
-
- InitAppleEvents
-
- Intialize our AppleEvent dispatcher table. For every pair of entries in
- keyWordsToInstall, we make a call to AEInstallEventHandler(). We use a common
- event dispatcher (called DispatchAppleEvent), which keys off of the refcon. So
- we load the refcon with the event ID.
-
- We also install a coercion handler to convert aliases to FSSpecs.
-
- *************************************************************************************/
- void InitAppleEvents(void)
- {
- OSErr err;
- long result;
- short i;
-
- gHasPPCToolbox = (Gestalt(gestaltPPCToolboxAttr, &result) ? false : result != 0);
-
- gHasAppleEvents = (Gestalt(gestaltAppleEventsAttr, &result) ? false : result != 0);
-
- if (gHasAppleEvents) {
- for (i = 0; i < (sizeof(keyWordsToInstall) / sizeof(pairs)); ++i)
- if ( err = AEInstallEventHandler(kCoreEventClass,
- keyWordsToInstall[i].theAEKeyWord,
- (ProcPtr) DispatchAppleEvent,
- keyWordsToInstall[i].theRefcon,
- false) ) {
- DisplayError(err, nil, "InitAppleEvents: Calling AEInstallEventHandler.");
- return;
- };
-
- if (err = AEInstallCoercionHandler(typeAlias, typeFSS, (ProcPtr) CoerceAliasToFSS,
- 0L, true, false) ) {
- DisplayError(err, nil, "InitAppleEvents: Trying to install CoerceAliasToFSS");
- return;
- };
- };
-
- }
-
-
- #pragma segment Main
- /**************************************************************************************
-
- CoerceAliasToFSS
-
- This is the routine used to convert aliases to FSSpecs. It is called by the
- AppleEvent Manager whenever we ask for an FSSpec, but it only has aliases. It
- is installed into the AppleEvent manager in InitAppleEvents() with a call to
- AEInstallCoercionHandler().
-
- Actually, I think an 'alis' -> 'fss ' coercion handler is built into the
- AppleEvent Manager, but this is still a good example of what to do.
-
- ***************************************************************************************/
- pascal OSErr CoerceAliasToFSS(AEDesc theAEDesc, DescType toType,
- long handlerRefcon, AEDesc *result)
- {
- #pragma unused (toType, handlerRefcon)
-
- OSErr err;
- FSSpec target;
- Boolean wasChanged;
-
- err = ResolveAlias(nil, (AliasHandle) theAEDesc.dataHandle, &target, &wasChanged);
- if (!err)
- err = AECreateDesc(typeFSS, (Ptr) &target, sizeof(FSSpec), result);
- return (err);
- }
-
- #pragma segment Main
- /**************************************************************************************
-
- MakeTarget
-
- Creates a TargetID for use in the AECreateAppleEvent call. If sendDirect is
- TRUE, the target is specified by setting a ProcessDerialNumber to
- kCurrentProcess. This has the advantage of sending the message directly to
- ourselves, by passing ePPC and gaining about a 10-15x speed improvement. If
- sendDirect is FALSE, we see if we have the PPCToolBox. If not, then we are
- forced to do a direct send. If we do have the PPCToolbox, then we call
- PPCBrowser. We then look at the reply, and factor in the mode we are going to
- use in AESend. If that mode is kAEWaitReply and the user selected us as the
- target, we have to turn that into a direct send. This is because the
- AppleEvent Manager will otherwise post the event as a high-level event.
- However, we are busy waiting for a reply, not looking for events, so we'll
- hang. We avoid this by forcing a direct send.
-
- ***************************************************************************************/
- OSErr MakeTarget(AEAddressDesc *target, Boolean sendDirect, short replyMode)
- {
- OSErr err = 0;
- ProcessSerialNumber targetPSN;
- ProcessSerialNumber myPSN;
- TargetID theTargetID;
- Boolean sendingToSelf;
-
- if (!sendDirect) {
- if (!gHasPPCToolbox) {
- sendDirect = true;
- }
- else {
- if (!(err = PPCBrowser(nil, nil, gDefaultOK, &gLocation, &gPortInfo, nil, nil))) {
- gDefaultOK = true;
- if (replyMode != kAEWaitReply) {
- sendDirect = false;
- }
- else {
- if (gLocation.locationKindSelector == 0) { /* sending to this machine */
- GetCurrentProcess(&myPSN);
- if (err = GetProcessSerialNumberFromPortName(&gPortInfo.name, &targetPSN))
- DisplayError(err, nil, "MakeTarget: getting our process serial number.");
- else if (err = SameProcess(&targetPSN, &myPSN, &sendingToSelf))
- DisplayError(err, nil, "MakeTarget: error calling SameProcess.");
- }
- else /* sending to some other machine, so it can't be us. */
- sendingToSelf = false;
-
- if (sendingToSelf) {
- DisplayError(0, nil, "MakeTarget: Cannot send to yourself through ePPC when using WaitReply mode. Using direct send instead.");
- sendDirect = true;
- }
- else
- sendDirect = false;
- }
- }
- }
- }
-
- if (!err) {
- if (sendDirect) {
- targetPSN.highLongOfPSN = 0;
- targetPSN.lowLongOfPSN = kCurrentProcess;
- err = AECreateDesc(typeProcessSerialNumber, (Ptr) &targetPSN, sizeof(targetPSN), target);
- if (err)
- DisplayError(err, nil, "MakeTarget: creating descriptor for target (1).");
- }
- else {
- theTargetID.location = gLocation;
- theTargetID.name = gPortInfo.name;
- err = AECreateDesc(typeTargetID, (Ptr) &theTargetID, sizeof(theTargetID), target);
- if (err)
- DisplayError(err, nil, "MakeTarget: creating descriptor for target (2).");
- }
- }
- return (err);
- }
-
-
- #pragma segment Main
- /*************************************************************************************
-
- MyIdleProc
-
- This routine gets either an updateEvt, an activateEvt, a nullEvent or an
- OSEvent. The first time called it will get a nullEvent; this is its chance to
- set the sleep value and mouseRegion that will be passed to WaitNextEvent by
- the caller within the AEM. After that it will also get events of the other
- types (which are lost if masked out by the AEM) and must do with them whatever
- is appropriate.
-
- **************************************************************************************/
- pascal Boolean MyIdleProc(EventRecord *event, long *sleepTime, RgnHandle *mouseRgn)
- {
- switch (event->what) {
-
- case updateEvt:
- case activateEvt:
- case kOSEvent:
-
- /* These events are passed by the AppleEvent manager to avoid dropping while
- waiting for a reply or notification. Every procedure should handle these
- events in their idle procedure. In this code, we simply dispatch these
- events back to the main event loop handling code. */
-
- AdjustCursor(event->where, gCursorRgn, false, 0);
- DoEvent(event);
- break;
-
-
- case nullEvent:
-
- /* The idle procedure is called once with the null event before the loop
- begins. This allows the application to alter sleep time and mouseRgn to meet
- its own needs. Since we're doing nothing, set the cursor to a watch. */
-
- AdjustCursor(event->where, gCursorRgn, true, 'wait');
-
- *mouseRgn = gCursorRgn;
- *sleepTime = 60; /* This is just like the WaitNextEvent sleeptime, so
- use the correct value for your application. It's
- better to use a non-zero value here rather than zero,
- as using zero really slows you down. */
- /* DoIdle(); */ /* ... this is the applications idle handling */
- break;
-
- default:
- DebugStr("\Got an event.what I'm not set up to handle.");
- break;
- }
- return(false);
- }
-
-
- #pragma segment Main
- /*************************************************************************************
-
- CreateAndSendAppleEvent
-
- Given an event ID, this routine creates such an event and posts it with
- AESend. Right now, all we know about are our own MoveWindow events and Echo
- events.
-
- **************************************************************************************/
- void CreateAndSendAppleEvent(AEEventID whichAppleEvent)
- {
-
- #define PRIORITY kAENormalPriority
-
- OSErr err;
- AppleEvent theAevt;
- AEAddressDesc theTarget;
- Point thePoint;
- short i;
- long startTime;
- AppleEvent theReply;
- short offsetForTitleBar = GetMBarHeight() + 20; /* actually, it's bad form
- to assume 20... */
-
- if (err = MakeTarget(&theTarget, gSendToSelf, gReplyMode)) {
- if (err != userCanceledErr)
- DisplayError(err, nil, "CreateAndSendAppleEvent: after MakeTarget.");
- }
- else {
- switch (whichAppleEvent) {
-
- /*
- Create the Window moved event. This is just a random point passed to
- the receiving application, which is expected to move the frontmost window
- to that point.
- */
-
- case traeMoveFrontWindowMsgID:
- thePoint.h = Random() % (qd.screenBits.bounds.right-6) + 1;
- thePoint.v = Random() % (qd.screenBits.bounds.bottom-6-offsetForTitleBar) + offsetForTitleBar;
-
- if ( thePoint.v < 0 )
- thePoint.v *= -1;
-
- if ( thePoint.h < 0 )
- thePoint.h *= -1;
-
- if (err = AECreateAppleEvent(kCoreEventClass, traeMoveFrontWindowMsgID, &theTarget,
- kAutoGenerateReturnID, kAnyTransactionID, &theAevt))
- DisplayError(err, nil, "CreateAndSendAppleEvent: after AECreateAppleEvent.");
-
- else if (err = AEPutParamPtr(&theAevt, keyDirectObject, typePoint, (Ptr) &thePoint, sizeof(Point)))
- DisplayError(err, nil, "CreateAndSendAppleEvent: after AEPutParamPtr.");
-
- else if (err = AESend(&theAevt, nil, kAENoReply, PRIORITY, 0, nil, nil)) {
- if (err == userCanceledErr) /* I hope this is right. The error
- used to be loginCancelErr, but
- that went away. */
- DisplayError(0, nil, "User Canceled logging on to destination computer.");
- else
- DisplayError(err, nil, "CreateAndSendAppleEvent: after AESend.");
- }
-
- if (err = AEDisposeDesc(&theAevt))
- DisplayError(err, nil, "CreateAndSendAppleEvent: after AEDisposeDesc of the AppleEvent.");
- break;
-
-
- /*
- Create and send an 'echo' message to the receiving application 1000 times.
- Clock the elapsed time, and display it when done.
- */
-
- case traeEchoID:
- if (err = AECreateAppleEvent(kCoreEventClass, traeEchoID, &theTarget,
- kAutoGenerateReturnID, kAnyTransactionID, &theAevt))
- DisplayError(err, nil, "CreateAndSendAppleEvent: after AECreateAppleEvent.");
-
-
- else {
-
- startTime = TickCount();
-
- for (i=0; (i<1000) && !err; ++i) {
-
- switch (gReplyMode) {
-
- case kAENoReply:
- if (err = AESend(&theAevt, nil,
- kAENoReply, PRIORITY,
- kNoTimeOut, nil, nil))
- DisplayError(err, nil, "CreateAndSendAppleEvent: after AESend.");
- break;
-
- case kAEWaitReply:
- if (err = AESend(&theAevt, &theReply,
- kAEWaitReply, PRIORITY,
- kNoTimeOut, (IdleProcPtr) MyIdleProc, nil))
- DisplayError(err, nil, "CreateAndSendAppleEvent: after AESend.");
- else if (err = AEDisposeDesc(&theReply))
- DisplayError(err, nil, "CreateAndSendAppleEvent: after AEDisposeDesc of the echo reply.");
- break;
-
- case kAEQueueReply:
- if (err = AESend(&theAevt, &theReply,
- kAEQueueReply, PRIORITY,
- kNoTimeOut, nil, nil)) {
- if (err == userCanceledErr) /* I hope this is right. The error
- used to be loginCancelErr, but
- that went away. */
- DisplayError(0, nil, "User Canceled logging on to destination computer.");
- else
- DisplayError(err, nil, "CreateAndSendAppleEvent: after AESend.");
- }
- else if (err = AEDisposeDesc(&theReply))
- DisplayError(err, nil, "CreateAndSendAppleEvent: after AEDisposeDesc of the echo reply.");
- break;
-
- default:
- DisplayError(gReplyMode, nil, "CreateAndSendAppleEvent: gReplyMode set to an unknown value.");
- break;
-
- }
- }
-
- ShowElapsedTime(TickCount() - startTime);
-
- if (err = AEDisposeDesc(&theAevt))
- DisplayError(err, nil, "CreateAndSendAppleEvent: after AEDisposeDesc of the AppleEvent.");
- }
- break;
-
- /*
- Duh...I don't know, George!
- */
-
- default:
- DisplayError(0, nil, "CreateAndSendAppleEvent: asked to send an event I don't know.");
- break;
- } /* switch */
-
- /*
- We created a descriptor for the target address. Better get rid of it.
- */
-
- if (err = AEDisposeDesc(&theTarget))
- DisplayError(err, nil, "CreateAndSendAppleEvent: after AEDisposeDesc of the target.");
-
- } /* if (error on MakeTarget) else ... */
- }
-
-
- #pragma segment Main
- /***************************************************************************************
-
- MoveTheFrontWindow
-
- Called when we recieve an AppleEvent with an ID of "traeMoveFrontWindowMsgID".
- It takes the point that's passed in the AppleEvent, and uses it to reposition
- the front window.
-
- *****************************************************************************************/
- OSErr MoveTheFrontWindow(AppleEvent message, AppleEvent reply, long refcon)
- {
- #pragma unused (reply, refcon)
-
- DescType actualType;
- Point pt;
- long actualSize;
- WindowPtr window = FrontWindow();
- OSErr err;
- short offsetForTitleBar = GetMBarHeight() + 20; /* actually, it's bad form to
- assume 20... */
-
- if ( IsAppWindow(window) ) {
- if (err = AEGetParamPtr(&message, keyDirectObject, typePoint,
- &actualType, (Ptr) &pt, sizeof(Point), &actualSize))
- DisplayError(err, nil, "MoveTheFrontWindow: after AEGetParamPtr.");
- else {
- if (pt.h > qd.screenBits.bounds.right-6)
- pt.h = qd.screenBits.bounds.right-6;
- if (pt.v > qd.screenBits.bounds.bottom-6)
- pt.v = qd.screenBits.bounds.bottom-6;
- else if (pt.v < offsetForTitleBar)
- pt.v = offsetForTitleBar;
-
- MoveWindow(window, pt.h, pt.v, true);
- }
- return (err);
- } else
- return (noErr);
- }
-
-
- #pragma segment Main
- /***************************************************************************************
-
- MissedAnyParameters
-
- Used to check for any unread required parameters. Returns true if we missed at
- least one.
-
- *****************************************************************************************/
- Boolean MissedAnyParameters(AppleEvent message)
- {
- OSErr err;
- DescType ignoredActualType;
- AEKeyword missedKeyword;
- Size ignoredActualSize;
- EventRecord event;
-
- err = AEGetAttributePtr(&message, keyMissedKeywordAttr, typeKeyword, &ignoredActualType,
- (Ptr) &missedKeyword, sizeof(missedKeyword), &ignoredActualSize);
-
- /* No error means that we found some more. */
-
- if (err == noErr) {
- event.message = *(long *) &ignoredActualType;
- event.where = *(Point *) &missedKeyword;
- DisplayError(err, &event, "MissedAnyParameters: got parameters I don't know what to do with.");
- err = errAEEventNotHandled;
- }
-
- /*
- errAEDescNotFound means that there are no more parameters. If we get
- an error code other than that, flag it.
- */
-
- else if (err != errAEDescNotFound) {
- DisplayError(err, nil, "MissedAnyParameters: after AEGetAttributeDesc.");
- }
-
- return (err != errAEDescNotFound);
- }
-
-
- #pragma segment Main
- /***************************************************************************************
-
- OpenDocEventHandler
-
- Called when we recieve an AppleEvent with an ID of "kAEOpenDocuments". This
- routine gets the direct parameter, parses it up into little FSSpecs, and opens
- each indicated file. It also shows the technique to be used in determining if
- you are doing everything the AppleEvent record is telling you. Parameters can
- be divided up into two groups: required and optional. Before executing an
- event, you must make sure that you've read all the required events. This is
- done by making an "any more?" call to the AppleEvent manager.
-
- *****************************************************************************************/
- OSErr OpenDocEventHandler(AppleEvent message, AppleEvent reply, Boolean forPrinting)
- {
- #pragma unused (reply)
-
- OSErr err;
- OSErr err2;
- AEDesc theDesc;
- FSSpec theFSS;
- short loopy;
- long numFilesToOpen;
- AEKeyword ignoredKeyWord;
- DescType ignoredType;
- Size ignoredSize;
-
- if (err = AEGetParamDesc(&message, keyDirectObject, typeAEList, &theDesc)) {
- DisplayError(err, nil, "OpenDocEventHandler: after AEGetParamDesc.");
- return(err);
- }
-
- if (!MissedAnyParameters(message)) {
-
- /*
- Got all the parameters we need. Now, go through the direct object,
- see what type it is, and parse it up.
- */
- if (err = AECountItems(&theDesc, &numFilesToOpen))
- DisplayError(err, nil, "OpenDocEventHandler: after AECountItems.");
- else {
- for (loopy = 1; ((loopy <= numFilesToOpen) && (!err)); ++loopy) {
- if (err = AEGetNthPtr(&theDesc, loopy, typeFSS, &ignoredKeyWord, &ignoredType,
- (Ptr) &theFSS, sizeof(theFSS), &ignoredSize))
- DisplayError(err, nil, "OpenDocEventHandler: after AEGetNthDesc.");
- else {
- if (!forPrinting)
- err = OpenFile(&theFSS);
- else
- err = PrintFile(&theFSS);
- }
- } /* for loopy = ... */
- } /* AECountItems OK */
- } /* Got all necessary parameters */
-
- if (err2 = AEDisposeDesc(&theDesc))
- DisplayError(err2, nil, "OpenDocEventHandler: after AEDisposeDesc of theDesc.");
-
- return(err ? err : err2);
- }
-
-
- #pragma segment Main
- /***************************************************************************************
-
- DispatchAppleEvent
-
- This routine is called by the AppleEvent manager to handle any events we
- registered with it. Because we registered the event with the event ID in the
- refcon, we can use the refcon in a switch statement. For each ID, we call to a
- routine to handle the event.
-
- This is really just one way of dispatching AppleEvents. Its advantages are
- that everything is in one place, and the code in InitAppleEventr used to set
- it up is simple. The disadvantage is that we have to case on the event ID
- number. The AppleEvent Manager already has to do this for us, so another way
- to handle this is to simply install a different routine for each message
- class/ID, and not use a case statement.
-
- *****************************************************************************************/
- pascal OSErr DispatchAppleEvent(AppleEvent message, AppleEvent reply, long refcon)
- {
- #define kTimeOutInTicks (60 * 120)
-
- switch ( refcon ) {
- case kAEOpenApplication:
- return (OpenNewWindow());
- case kAEOpenDocuments:
- return (OpenDocEventHandler(message, reply, false));
- case kAEPrintDocuments:
- if (!AEInteractWithUser(kTimeOutInTicks, nil, (IdleProcPtr) MyIdleProc))
- PresentStyleDialog();
- return (OpenDocEventHandler(message, reply, true));
- case kAEQuitApplication:
- Terminate();
- return (noErr);
- case kAEAnswer:
- return (noErr);
- case traeEchoID:
- return (noErr);
- case traeMoveFrontWindowMsgID:
- return (MoveTheFrontWindow(message, reply, refcon));
- default:
- return (errAEEventNotHandled);
- }
- }
-
-
- #pragma segment Main
- /***************************************************************************************
-
- DoHighLevelEvent
-
- Simply calls AEProcessAppleEvent and reports any errors. AEProcessAppleEvent
- looks in its table of registered events and sees if the current event is
- registered. If so, it calls the routine associated with that event. In our
- case, we set that to DispatchAppleEvent.
-
- *****************************************************************************************/
- void DoHighLevelEvent(EventRecord *event)
- {
- OSErr err;
-
- if ( err = AEProcessAppleEvent(event) )
- DisplayError(err, event, "DoHighLevelEvent: After AEProcessAppleEvent");
- }
-